package org.xinjiang.data.migration.common.date;

import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.DateUtils;

import java.text.ParseException;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalAdjusters;
import java.util.Date;

/**
 * 时间工具类
 *
 * @author wenjie
 * @date 2022/11/25
 */
public interface Dates {
    ZoneOffset DEFAULT_ZONE_ID = ZoneOffset.ofHours(8);

    String PATTERN_DATETIME = "uuuu-MM-dd HH:mm:ss";

    String PATTERN_DATE = "uuuu-MM-dd";

    String PATTERN_TIME = "HH:mm:ss";

    String PATTERN_DATETIME2 = "yyyy-MM-dd'T'HH:mm:ss.SSSX";

    DateTimeFormatter DATETIME_FORMAT = DateTimeFormatter.ofPattern(PATTERN_DATETIME);

    DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern(PATTERN_DATE);

    DateTimeFormatter DATE_FORMAT2 = DateTimeFormatter.ofPattern(PATTERN_DATETIME2);

    DateTimeFormatter TIME_FORMAT = DateTimeFormatter.ofPattern(PATTERN_TIME);

    static Date formatStartTime(Date date) {
        String str = DateFormatUtils.format(date, PATTERN_DATE);
        try {
            date = DateUtils.parseDate(str, PATTERN_DATE);
        } catch (ParseException e) {
            throw new RuntimeException("日期格式化错误", e);
        }
        return date;
    }

    static Date formatEndTime(Date date) {
        String str = DateFormatUtils.format(date, PATTERN_DATE) + " 23:59:59";
        try {
            date = DateUtils.parseDate(str, PATTERN_DATETIME);
        } catch (ParseException e) {
            throw new RuntimeException("日期格式化错误", e);
        }
        return date;
    }

    static LocalDateTime formatStartTime(LocalDateTime dateTime) {
        return dateTime.with(LocalTime.MIN);
    }

    static LocalDateTime formatEndTime(LocalDateTime dateTime) {
        return dateTime.with(LocalTime.MAX);
    }

    static Date localDate2Date(LocalDate localDate) {
        if (null == localDate) {
            return null;
        }
        ZonedDateTime zonedDateTime = localDate.atStartOfDay(DEFAULT_ZONE_ID);
        return Date.from(zonedDateTime.toInstant());
    }

    static Date localDateTime2Date(LocalDateTime dateTime) {
        if (null == dateTime) {
            return null;
        }
        return Date.from(dateTime.atZone(DEFAULT_ZONE_ID).toInstant());
    }

    static LocalDate date2LocalDate(Date date) {
        if (null == date) {
            return null;
        }
        return date.toInstant().atZone(DEFAULT_ZONE_ID).toLocalDate();
    }

    static LocalTime date2LocalTime(Date date) {
        if (null == date) {
            return null;
        }
        return date.toInstant().atZone(DEFAULT_ZONE_ID).toLocalTime();
    }

    static LocalDateTime date2LocalDateTime(Date date) {
        if (null == date) {
            return null;
        }
        return date.toInstant().atZone(DEFAULT_ZONE_ID).toLocalDateTime();
    }

    static Long localDateTime2Long(LocalDateTime localDateTime) {
        if (null == localDateTime) {
            return null;
        }
        return localDateTime.toInstant(DEFAULT_ZONE_ID).toEpochMilli();
    }

    static Long localDate2Long(LocalDate localDate) {
        if (null == localDate) {
            return null;
        }
        return localDate.atStartOfDay(DEFAULT_ZONE_ID).toInstant().toEpochMilli();
    }

    static LocalDateTime long2LocalDateTime(Long timeStamp) {
        if (null == timeStamp) {
            return null;
        }
        return date2LocalDateTime(new Date(timeStamp));
    }

    static LocalDate long2LocalDate(Long timeStamp) {
        if (null == timeStamp) {
            return null;
        }
        return date2LocalDate(new Date(timeStamp));
    }

    /**
     * 本月 第一天
     */
    static LocalDate firstDayOfMonth(LocalDate day) {
        return day.with(TemporalAdjusters.firstDayOfMonth());
    }

    /**
     * 本月 最后一天
     */
    static LocalDate lastDayOfMonth(LocalDate day) {
        return day.with(TemporalAdjusters.lastDayOfMonth());
    }

    /**
     * 本月 多少天
     */
    static LocalDate dayOfMonth(LocalDate day, int dayOfMonth) {
        return day.withDayOfMonth(dayOfMonth);
    }

    /**
     * 下个月
     */
    static LocalDate firstDayOfNextMonth(LocalDate day) {
        return day.with(TemporalAdjusters.firstDayOfNextMonth());
    }

    /**
     * 下个月
     */
    static LocalDateTime firstDayOfNextMonth(LocalDateTime dateTime) {
        return dateTime.with(TemporalAdjusters.firstDayOfNextMonth());
    }

    /**
     * 本年 多少天
     */
    static LocalDate dayOfYear(LocalDate day, int dayOfYear) {
        return day.withDayOfYear(dayOfYear);
    }

    /**
     * 增加天数（负数为减少）
     */
    static LocalDate daysToAdd(LocalDate day, int daysToAdd) {
        return day.plusDays(daysToAdd);
    }

    static Long duration(Date s, Date e) {
        return (e.getTime() - s.getTime()) / (1000 * 60);
    }

    static boolean isSameDate(LocalDateTime dt1, LocalDateTime dt2) {
        return isSameDate(dt1.toLocalDate(), dt2.toLocalDate());
    }

    static boolean isSameDate(LocalDate d1, LocalDate d2) {
        return betweenDays(d1, d2) == 0;
    }

    static long betweenDays(LocalDate d1, LocalDate d2) {
        return ChronoUnit.DAYS.between(d1, d2);
    }

    static long betweenDays(LocalDateTime d1, LocalDateTime d2) {
        return ChronoUnit.DAYS.between(d1, d2);
    }

    static long betweenMinutes(LocalDateTime d1, LocalDateTime d2) {
        return ChronoUnit.MINUTES.between(d1, d2);
    }

    static long betweenMinutes(LocalTime d1, LocalTime d2) {
        return ChronoUnit.MINUTES.between(d1, d2);
    }

    static long betweenHours(LocalDateTime d1, LocalDateTime d2) {
        return ChronoUnit.HOURS.between(d1, d2);
    }

    static long betweenSeconds(LocalDateTime d1, LocalDateTime d2) {
        return ChronoUnit.SECONDS.between(d1, d2);
    }

    static long betweenHours(LocalTime d1, LocalTime d2) {
        return ChronoUnit.HOURS.between(d1, d2);
    }

    static long parkingDuration(LocalDateTime d1, LocalDateTime d2) {
        return parkingDuration(betweenMinutes(d1, d2));
    }

    /**
     * 分钟转换为小时(超过1分钟算1个小时)
     */
    static long parkingDuration(long minutes) {
        long hours = minutes / 60;
        return minutes % 60 > 0 ? hours + 1 : hours;
    }


    /**
     * 日期时间格式化
     */
    static String formatDateTime(TemporalAccessor temporal) {
        return DATETIME_FORMAT.format(temporal);
    }

    /**
     * 日期时间格式化
     */
    static String formatDate(TemporalAccessor temporal) {
        return DATE_FORMAT.format(temporal);
    }

    /**
     * 时间格式化
     */
    static String formatTime(TemporalAccessor temporal) {
        return TIME_FORMAT.format(temporal);
    }

    /**
     * 日期格式化
     */
    static String format(TemporalAccessor temporal, String pattern) {
        return DateTimeFormatter.ofPattern(pattern).format(temporal);
    }

    /**
     * 将字符串转换为时间
     */
    static TemporalAccessor parse(String dateStr, String pattern) {
        DateTimeFormatter format = DateTimeFormatter.ofPattern(pattern);
        return format.parse(dateStr);
    }

    /**
     * 将字符串转换为时间
     */
    static TemporalAccessor parse(String dateStr, DateTimeFormatter formatter) {
        return formatter.parse(dateStr);
    }

    /**
     * 将字符串转换为日期时间
     */
    static LocalDateTime parseDateTime(String s) {
        return LocalDateTime.parse(s, DATETIME_FORMAT);
    }

    /**
     * 将字符串转换为日期时间
     */
    static LocalDateTime parseDateTime(String s, DateTimeFormatter formatter) {
        return LocalDateTime.parse(s, formatter);
    }

    /**
     * 将字符串转换为日期
     */
    static LocalDate parseDate(String s) {
        return LocalDate.parse(s, DATE_FORMAT);
    }

    /**
     * 将字符串转换为日期
     */
    static LocalDate parseDate(String s, DateTimeFormatter formatter) {
        return LocalDate.parse(s, formatter);
    }

    /**
     * 将字符串转换为时间
     */
    static LocalTime parseTime(String s) {
        return LocalTime.parse(s, TIME_FORMAT);
    }

    /**
     * 将字符串转换为时间
     */
    static LocalTime parseTime(String s, DateTimeFormatter formatter) {
        return LocalTime.parse(s, formatter);
    }

    /**
     * 时间转 Instant
     */
    static Instant toInstant(LocalDateTime dateTime) {
        return dateTime.atZone(ZoneId.systemDefault()).toInstant();
    }

    /**
     * Instant 转 时间
     */
    static LocalDateTime toDateTime(Instant instant) {
        return LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
    }

    /**
     * 获取毫秒
     */
    static long milli(LocalDateTime dateTime) {
        return toInstant(dateTime).toEpochMilli();
    }

    /**
     * 获取秒
     */
    static long second(LocalDateTime dateTime) {
        return toInstant(dateTime).getEpochSecond();
    }

    /**
     * 毫秒 转换 日期时间
     */
    static LocalDateTime milliToLocalDateTime(Long milli) {
        return toDateTime(Instant.ofEpochMilli(milli));
    }

    /**
     * 秒 转换 日期时间
     */
    static LocalDateTime secondToLocalDateTime(Long second) {
        return toDateTime(Instant.ofEpochSecond(second));
    }

}
